package com.eulog.client.blackJack;

import java.util.ArrayList;

import com.eulog.client.blackJack.BlackJackStrategy.SD;
import com.eulog.client.trump.TrumpCard;
import com.eulog.client.trump.TrumpCard.Rank;
import com.eulog.client.trump.TrumpCard.Suit;

public class BlackJack {
	
	
	BlackJackDealer dealer;
	ArrayList<BlackJackPlayer> players;
	ArrayList<BlackJackDecks> decksHistory;
	BlackJackDecks currentDecks;
	int deckSize;
	float playerNaturalAdvantage;
	BlackJackRules rules;
	
	public BlackJack(int _deckSize,float naturalAdvantage) {
		dealer = new BlackJackDealer(0);
		players = new ArrayList<BlackJackPlayer>();
		decksHistory = new ArrayList<BlackJackDecks>();
		deckSize = _deckSize;
		playerNaturalAdvantage = naturalAdvantage;
		
		//Blackjack Rules
		rules = new BlackJackRules(false,true);
		
		getNewDecks();
	}
	
	
	
	public void play() {
		if(players.size()>0) {
			
			//Deal initial cards for players and Bet
			for (BlackJackPlayer player: players) {
				player.setCurrentBetByCountingStrategy(currentDecks.getBlackJackStrategy());
				player.clearCard();
				player.addHandCard(deal());
				player.addHandCard(deal());
			}
			
			//Deal initial cards for Dealer
			dealer.clearCard();
			dealer.addHandCard(deal());
			dealer.addHandCard(deal());
			
			// Get Decisions from players
			BlackJackStrategy.SD decision;
			//boolean doubledDown;
			if(dealer.isBlackJack(0)==false) {
				for (BlackJackPlayer player : players) {
					if(player.isBlackJack(0)==false) {
						for(int i=0; i<=player.getSplitCount(); i++) {
							do {
								decision = player.getNextDecision(currentDecks.getBlackJackStrategy(),dealer.getOpenCard(),i,rules);
								//doubledDown = false;
								
								if(player.getCardSize(i)<2) {
									decision = SD.H;
									player.addHandCard(deal(),i);
								}
								else {
									if(decision == SD.H) {
										player.addHandCard(deal(),i);
									}
									else if(decision == SD.D) {
										if(player.canDoublingDown(i)) {
											player.doublingDown(i);
											//doubledDown = true;
										}
										else {
											decision = SD.H;
										}
										player.addHandCard(deal(),i);
										
									}
									else if(decision == SD.X) {
										if(player.canDoublingDown(i)) {
											player.doublingDown(i);						
											player.addHandCard(deal(),i);
											//doubledDown = true;
										}
									}
									else if(decision == SD.P) {
										if(player.canSplit(i)) {
											int newSplitIndex = player.split(i);
											if(newSplitIndex>0) {
												player.addHandCard(deal(),i);
												player.addHandCard(deal(),newSplitIndex);
											}
										}
										else {
											decision = SD.S;
										}
									}
									player.addDecision(decision, i);
								}
							//} while (decision == SD.H || doubledDown || decision == SD.P );
							} while ( (decision == SD.H && (player.isBusted(i)==false) ) || decision == SD.P );
						}
					}
				}
	
				// Get Decisions from dealer
				do {
					decision = dealer.getNextDecision(currentDecks.getBlackJackStrategy(),dealer.getOpenCard(),0,rules);
					if(decision == SD.H) dealer.addHandCard(deal(),0);
				} while (decision == SD.H);
			}
			
			//calculate
			int result;
			int splitNum;
			for (BlackJackPlayer player : players) {
				splitNum = player.getSplitCount();
				
				for(int i=0; i<=splitNum; i++) {
					player.addTotalAmountOfBet( player.getCurrentBet()+player.getAdditionalBet(i));
					result = doesPlayerWin(player,i);
					if(result == 1) {
						float advantage;
						if(player.isBlackJack(i)) advantage = playerNaturalAdvantage;
						else advantage = 1;
							
						player.wonAgainst(dealer, advantage * (player.getCurrentBet()+player.getAdditionalBet(i)));
					}
					else if(result == -1) {
						player.lostAgainst(dealer, player.getCurrentBet()+player.getAdditionalBet(i));
					}
					else {
						player.tieAgainst(dealer);
					}
				}
			}
		}
	}
	
	public String toStringCurrentGame() {
		String status = "";
		
		status += dealer.toString();
		status += " : ";
		
		for (BlackJackPlayer player: players) {
			status += player.toString();
			status += "  (" + player.getCurrentMoney() + "," + player.getCurrentBet() + ") ";
			status += " +=+ ";
		}
		
		return status;
	}
	
	public int doesPlayerWin(BlackJackPlayer player, int splitNo) {
		if(player.isBusted(splitNo)) return -1;
		if(dealer.isBusted(0)) return 1;
		
		if(dealer.isBlackJack(0) && player.isBlackJack(splitNo)==false) return -1;
		
		int result = compareCards(player.calculateRanks(splitNo),player.getCardSize(splitNo), dealer.calculateRanks(0),dealer.getCardSize(0));
		if(result<0) return -1;
		if(result>0) return 1;
		
		return 0;
	}
	
	public TrumpCard deal() {
		if(currentDecks.isCardAvailable(1)==false) {
			getNewDecks();
		}
		
		return currentDecks.dealOneCard();
	}
	
	public BlackJackDecks getCurrentDecks() {return currentDecks;}
	
	public void addPlayer(BlackJackPlayer newplayer) {players.add(newplayer);}
	
	public void getNewDecks() {
		currentDecks = new BlackJackDecks(deckSize,true,deckSize*52-26,rules);
		//currentDecks = new BlackJackDecks(deckSize,true,0);
		decksHistory.add(currentDecks);
	}
	
	public static int evaluateRank(TrumpCard card) {
		int rank = 0;
		
		switch(card.rank()) {
		case DEUCE:
			rank = 2;
			break;
		case THREE:
			rank = 3;
			break;
		case FOUR:
			rank = 4;
			break;
		case FIVE:
			rank = 5;
			break;
		case SIX:
			rank = 6;
			break;
		case SEVEN:
			rank = 7;
			break;
		case EIGHT:
			rank = 8;
			break;
		case NINE:
			rank = 9;
			break;
		case TEN:
			rank = 10;
			break;
		case JACK:
			rank = 10;
			break;
		case QUEEN:
			rank = 10;
			break;
		case KING:
			rank = 10;
			break;
		case ACE:
			rank = 11;
			break;
		}

		
		return rank;
	}
	
	public static Rank getRankByEvaluation(int e) {
		Rank rank;
		
		switch(e) {
		case 2:
			rank = Rank.DEUCE;
			break;
		case 3:
			rank = Rank.THREE;
			break;
		case 4:
			rank = Rank.FOUR;
			break;
		case 5:
			rank = Rank.FIVE;
			break;
		case 6:
			rank = Rank.SIX;
			break;
		case 7:
			rank = Rank.SEVEN;
			break;
		case 8:
			rank = Rank.EIGHT;
			break;
		case 9:
			rank = Rank.NINE;
			break;
		case 10:
			rank = Rank.TEN;
			break;
		default:
			rank = Rank.ACE;
			break;
		}
		
		return rank;
	}

	public static TrumpCard getCardByEvaluation(int eval) {
		if(eval==11) eval=1;
		return getCardByRank(TrumpCard.getRankByValue(eval));
	}
	
	public static TrumpCard getCardByRank(Rank r) {
		return TrumpCard.getTrumpCard(Suit.DIAMONDS, r);
	}
	
	public static int compareCards(int cards1Rank,int cards1Size, int cards2Rank,int cards2Size) {
		
		if(cards1Rank > cards2Rank) {
			return 1;
		}
		else if(cards1Rank < cards2Rank) {
			return -1;
		}
		else if(cards1Rank == 21) {
			if(cards1Size == 2 && cards2Size > 2) return 1; 
			if(cards1Size > 2 && cards2Size == 2) return -1;
		}
		
		return 0;
	}
}
